import { Vector3 } from "@minecraft/server";
import { CubeRegion } from "@sapi-game/gameRegion/gameRegion";
import { Vector3Utils } from "@sapi-game/utils";

/** 电梯运行方向 */
export enum EleDirection {
    Down = -1,
    Idle = 0,
    Up = 1,
}

/** 电梯配置 */
export interface ElevatorConfig {
    maxFloor: number;
    initFloor?: number;
    /**基坐标 */
    baseLoc: Vector3;
    /**电梯内区域 */
    region: CubeRegion;
    /**开关门按钮偏移 */
    opeButtonOffset?: Vector3;
    /**呼叫按钮偏移 */
    callButtonOffset?: Vector3;

    /**每层楼时间 */
    timePerFloor?: number;
    /**开关门所需时间 */
    timeDoorCycle?: number;
    /**开门时长 */
    timeDoorOpen?: number;
}
/** 电梯状态 */
export interface ElevatorState {
    floor: number;
    direction: EleDirection;
    doorOpen: boolean;
}

export enum ElevatorEventType {
    Moving = "moving",
    Move = "arrive",
    Open = "open",
    Close = "close",
}

export interface ElevatorEvent {
    type: ElevatorEventType;
    state: ElevatorState;
}

/** 电梯逻辑类 */
export class Elevator {
    public readonly config: Required<ElevatorConfig>;
    private floor: number;
    private direction: EleDirection = EleDirection.Idle;

    private upList: number[] = [];
    private downList: number[] = [];
    private goList: number[] = [];

    private moveTimeCnt: number;
    private stopTime: number = 0;
    private doorOpen: boolean = false;
    public doorAnimating: boolean = false;

    constructor(config: ElevatorConfig) {
        this.config = {
            maxFloor: config.maxFloor,
            initFloor: config.initFloor ?? 1,
            timePerFloor: config.timePerFloor ?? 2,
            timeDoorCycle: config.timeDoorCycle ?? 1,
            timeDoorOpen: config.timeDoorOpen ?? 3,
            baseLoc: config.baseLoc,
            region: config.region,
            opeButtonOffset: config.opeButtonOffset ?? { x: 0, y: 0, z: -3 },
            callButtonOffset: config.callButtonOffset ?? { x: 3, y: 0, z: -3 },
        };
        this.floor = this.config.initFloor;
        this.moveTimeCnt = this.config.timePerFloor;
    }

    /** 外部订阅的事件监听器 */
    private listeners: ((event: ElevatorEvent) => void)[] = [];

    /** 订阅事件 */
    onEvent(listener: (event: ElevatorEvent) => void) {
        this.listeners.push(listener);
    }

    clearEvent() {
        this.listeners = [];
    }

    /** 触发事件 */
    private emit(type: ElevatorEventType) {
        this.listeners.forEach((l) =>
            l({ type: type, state: this.getState() })
        );
    }

    /** 获取当前电梯状态 */
    getState(): ElevatorState {
        return {
            floor: this.floor,
            direction: this.direction,
            doorOpen: this.doorOpen,
        };
    }

    /**获取内部按下的楼层(副本) */
    getGoList() {
        return this.goList.slice();
    }

    get baseLoc() {
        return this.config.baseLoc;
    }

    get callButtonLoc() {
        return Vector3Utils.add(this.baseLoc, this.config.callButtonOffset);
    }

    get opeButtonLoc() {
        return Vector3Utils.add(this.baseLoc, this.config.opeButtonOffset);
    }

    /** 外部呼叫电梯 (用户按了上/下按钮) */
    call(floor: number, dir: EleDirection.Up | EleDirection.Down) {
        if (floor < 1 || floor > this.config.maxFloor) return;
        if (dir === EleDirection.Up) {
            if (!this.upList.includes(floor)) this.upList.push(floor);
            this.upList.sort((a, b) => a - b);
        } else {
            if (!this.downList.includes(floor)) this.downList.push(floor);
            this.downList.sort((a, b) => b - a);
        }
    }

    /** 添加内部直达请求 */
    innerGo(floor: number) {
        if (floor < 1 || floor > this.config.maxFloor) return;
        if (this.goList.includes(floor)) return;
        this.goList.push(floor);
    }
    /**删除内部直达请求 */
    removeGo(floor: number) {
        this.goList = this.goList.filter((f) => f != floor);
    }

    /**内部开门 */
    innerOpen() {
        if (this.doorAnimating) return;
        this.openDoor();
    }

    /**内部关门 */
    innerClose() {
        if (this.doorAnimating) return;
        //开门状态直接关门
        if (this.doorOpen) {
            this.closeDoor();
        }
    }

    /** 主循环，每 tick 调用一次 */
    tick() {
        // 电梯在开门或关门等待
        if (this.stopTime > 0) {
            this.stopTime--;
            return;
        }

        // 处理目标到达
        if (this.shouldStopAtCurrentFloor()) {
            this.openDoor();
            return;
        }

        // 如果门开着，先关门
        if (this.doorOpen) {
            this.closeDoor();
            return;
        }

        //改变方向
        this.changeDirection();

        this.move();
    }

    /** 是否应在当前楼层停靠 */
    private shouldStopAtCurrentFloor(): boolean {
        return (
            this.upList.includes(this.floor) ||
            this.downList.includes(this.floor) ||
            this.goList.includes(this.floor)
        );
    }

    private changeDirection() {
        const allCalls = Array.from(
            new Set([...this.goList, ...this.downList, ...this.upList])
        );
        const callBelow = allCalls.filter((c) => c < this.floor);
        const callAbove = allCalls.filter((c) => c > this.floor);

        if (this.direction == EleDirection.Down && callBelow.length == 0) {
            this.direction =
                callAbove.length == 0 ? EleDirection.Idle : EleDirection.Up;
            return;
        }
        if (this.direction == EleDirection.Up && callAbove.length == 0) {
            this.direction =
                callBelow.length == 0 ? EleDirection.Idle : EleDirection.Down;
            return;
        }
        if (this.direction == EleDirection.Idle) {
            if (this.goList.length != 0) {
                this.direction =
                    this.goList[0] > this.floor
                        ? EleDirection.Up
                        : EleDirection.Down;
            } else if (callAbove.length || callBelow.length) {
                this.direction = callAbove.length
                    ? EleDirection.Up
                    : EleDirection.Down;
            }
        }
    }

    /** 开门 */
    private openDoor() {
        this.upList = this.upList.filter((f) => f !== this.floor);
        this.downList = this.downList.filter((f) => f !== this.floor);
        this.goList = this.goList.filter((f) => f !== this.floor);
        const openTime = this.config.timeDoorCycle + this.config.timeDoorOpen;
        if (this.doorOpen) {
            this.stopTime = openTime;
            return;
        }
        this.doorOpen = true;
        this.stopTime = openTime;
        this.emit(ElevatorEventType.Open);
    }

    /** 关门 */
    private closeDoor() {
        this.doorOpen = false;
        this.emit(ElevatorEventType.Close);
        this.stopTime = this.config.timeDoorCycle;
    }

    /** 移动一层 */
    private move() {
        if (this.direction === EleDirection.Idle) return;

        if (
            (this.floor === this.config.maxFloor &&
                this.direction === EleDirection.Up) ||
            (this.floor === 1 && this.direction === EleDirection.Down)
        ) {
            this.direction = EleDirection.Idle;
            return;
        }

        if (this.moveTimeCnt > 0) {
            this.moveTimeCnt--;
            this.emit(ElevatorEventType.Moving);
        } else {
            this.floor += this.direction;
            this.moveTimeCnt = this.config.timePerFloor - 1;
            this.emit(ElevatorEventType.Move);
        }
    }
}
